package com.dotools.utils;

import android.text.TextUtils;

import com.dotools.debug.LOG;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/***
 * 获取文件的sha1值，用于校验文件下载的完整性
 *
 * @author wuxiaojun
 */
public class FileSha1Utils {

    // 将字节转换为十六进制字符串
    private static String byteToHexString(byte ib) {
        char[] Digit = {
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
                'D', 'E', 'F'
        };
        char[] ob = new char[2];
        ob[0] = Digit[(ib >>> 4) & 0X0F];
        ob[1] = Digit[ib & 0X0F];
        String s = new String(ob);
        return s;
    }

    // 将字节数组转换为十六进制字符串
    private static String byteArrayToHexString(byte[] bytearray) {
        String strDigest = "";
        for (int i = 0; i < bytearray.length; i++) {
            strDigest += byteToHexString(bytearray[i]);
        }
        return strDigest;
    }

    /**
     * 适用于上G大的文件
     */
    public static String getFileSha1(String path) throws OutOfMemoryError, IOException {
        File file = new File(path);
        FileInputStream in = new FileInputStream(file);
        MessageDigest messagedigest;
        try {
            messagedigest = MessageDigest.getInstance("SHA-1");
            byte[] buffer = new byte[1024 * 1024 * 10];
            int len = 0;
            while ((len = in.read(buffer)) > 0) {
                // 该对象通过使用 update（）方法处理数据
                messagedigest.update(buffer, 0, len);
            }
            // 对于给定数量的更新数据，digest 方法只能被调用一次。在调用 digest 之后，MessageDigest
            // 对象被重新设置成其初始状态。
            return byteArrayToHexString(messagedigest.digest());
        } catch (NoSuchAlgorithmException e) {
            LOG.logE("getFileSha1->NoSuchAlgorithmException###", e);
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            LOG.logE("getFileSha1->OutOfMemoryError###", e);
            e.printStackTrace();
            throw e;
        } finally {
            in.close();
        }
        return null;
    }

    /***
     * 获取文件sha1值
     * @param file
     * @return
     */
    public static String getSHA1(File file){
        if(file != null && file.exists()){
            try {
                InputStream is = new FileInputStream(file);
                if(is != null){
                    String sha1 = getSHA1(is);
                    if(!TextUtils.isEmpty(sha1)){
                        return sha1;
                    }
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 获取文件SHA1摘要值
     */
    public static String getSHA1(InputStream fileInputStream) {
        // 缓冲区大小
        int bufferSize = 256 * 1024;
        DigestInputStream digestInputStream = null;
        try {
            // 拿到一个SHA1转换器（这里可以换成MD5）
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            // 使用DigestInputStream
            digestInputStream = new DigestInputStream(fileInputStream, messageDigest);
            // read的过程中进行SHA1处理，直到读完文件
            byte[] buffer = new byte[bufferSize];
            while (digestInputStream.read(buffer) > 0)
                ;
            // 获取最终的MessageDigest
            messageDigest = digestInputStream.getMessageDigest();
            // 拿到结果，也是字节数组，包含16个元素
            byte[] resultByteArray = messageDigest.digest();
            // 把字节数组转换成字符串
            return byteArrayToHex(resultByteArray);
        } catch (Exception e) {
            return null;
        } finally {
            try {
                close(digestInputStream);
                close(fileInputStream);
            } catch (Exception e) {

            }
        }
    }

    /**
     * 将字节数组换成成16进制的字符串
     */
    public static String byteArrayToHex(byte[] byteArray) {
        // 首先初始化一个字符数组，用来存放每个16进制字符
        char[] hexDigits =
                {
                        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
                };
        // new一个字符数组，这个就是用来组成结果字符串的（解释一下：一个byte是八位二进制，也就是2位十六进制字符（2的8次方等于16的2次方））
        char[] resultCharArray = new char[byteArray.length * 2];
        // 遍历字节数组，通过位运算（位运算效率高），转换成字符放到字符数组中去
        int index = 0;
        for (byte b : byteArray) {
            resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b & 0xf];
        }
        // 字符数组组合成字符串返回
        return new String(resultCharArray).toLowerCase();
    }

    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
            }
        }
    }

}
